package com.dkd.flow.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dkd.common.core.domain.entity.SysUser;
import com.dkd.flow.domain.EProcessDefinition;
import com.dkd.flow.domain.EProcessInstances;
import com.dkd.flow.domain.EProcessTask;
import com.dkd.flow.emums.FlowType;
import com.dkd.flow.emums.NodeType;
import com.dkd.flow.emums.TaskStatus;
import com.dkd.flow.mapper.EProcessDefinitionMapper;
import com.dkd.flow.mapper.EProcessInstancesMapper;
import com.dkd.flow.mapper.EProcessTaskMapper;
import com.dkd.flow.rules.BaseRules;
import com.dkd.flow.rules.conditions.ConditionsRule;
import com.dkd.system.service.impl.SysUserServiceImpl;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@Component
public class NodeUtils {
    @Autowired
    TaskCreate taskCreate;
    @Autowired
    EProcessInstancesMapper eProcessInstancesMapper;
    @Autowired
    EProcessTaskMapper eProcessTaskMapper;
    @Autowired
    ConditionsRule conditionsRule;
    @Autowired
    BaseRules baseRules;
    @Autowired
    public NodeUtils nodeUtils;
    @Autowired
    SysUserServiceImpl sysUserServiceImpl;
    @Autowired
    EProcessDefinitionMapper eProcessDefinitionMapper;
    private List<JSONObject> nodes = new ArrayList<>();
    private List<JSONObject> links = new ArrayList<>();
    private List<String> lastArr = new ArrayList<>();

    void clear() {
        nodes.clear();
        links.clear();
        lastArr.clear();
    }

    private JSONObject getUnRelationNode(JSONObject res) {
        JSONObject properties = res.getJSONObject("properties");
        String nodeName = properties.getString("title");
        String content = res.getString("content");
        String type = res.getString("type");
        if ("start".equals(type)) {
            content = "";
        }
        if (!res.containsKey("nodeId")) {
            return null;
        }
        JSONObject node = new JSONObject();
        node.put("key",
                res.getString("nodeId"));
        if ("copy".equals(type)) {
            String str = nodeName + "\n抄送：" + content;
            if ("抄送人".equals(nodeName)) {
                str = "抄送：" + content;
            }
            node.put("text",
                    str);
        } else if ("condition".equals(type)) {
            if ("请设置条件".equals(content)) {
                content = "无";
            }
            node.put("text",
                    nodeName.replace("条件",
                            "分支") + "\n条件：" + content);
        } else {
            node.put("text",
                    nodeName + "\n" + content);
        }
        node.put("node",
                res);
        return node;
    }

    private void findLast(JSONObject res) {
        JSONArray conditionNodes = res.getJSONArray("conditionNodes");
        JSONObject childNode = res.getJSONObject("childNode");
        if (childNode == null && (conditionNodes == null || conditionNodes.isEmpty())) {
            lastArr.add(res.getString("nodeId"));
        } else if (childNode == null && conditionNodes != null) {
            for (int i = 0; i < conditionNodes.size(); i++) {
                JSONObject b = conditionNodes.getJSONObject(i);
                if (b.containsKey("childNode")) {
                    findLast(b.getJSONObject("childNode"));
                } else {
                    lastArr.add(b.getString("nodeId"));
                }
            }
        } else {
            findLast(childNode);
        }
    }

    private void relative(JSONObject res) {
        JSONArray conditionNodes = res.getJSONArray("conditionNodes");
        JSONObject childNode = res.getJSONObject("childNode");
        if (childNode != null && (conditionNodes == null || conditionNodes.isEmpty())) {
            childNode.put("fid",
                    new JSONArray(Collections.singletonList(res.getString("nodeId"))));
            childNode.put("nid",
                    new JSONArray(Collections.singletonList(childNode.getString("nodeId"))));
        } else if (childNode == null && conditionNodes != null) {
            for (int i = 0; i < conditionNodes.size(); i++) {
                JSONObject a = conditionNodes.getJSONObject(i);
                a.put("fid",
                        new JSONArray(Collections.singletonList(res.getString("nodeId"))));
                a.put("nid",
                        new JSONArray(Collections.singletonList(a.getString("nodeId"))));
            }
        } else if (childNode != null) {
            lastArr.clear();
            for (int i = 0; i < conditionNodes.size(); i++) {
                JSONObject a = conditionNodes.getJSONObject(i);
                a.put("fid",
                        new JSONArray(Collections.singletonList(res.getString("nodeId"))));
                a.put("nid",
                        new JSONArray(Collections.singletonList(a.getString("nodeId"))));
                findLast(a);
            }
            childNode.put("fid",
                    new JSONArray(lastArr));
            childNode.put("nid",
                    new JSONArray(Collections.singletonList(childNode.getString("nodeId"))));
        }
        if (childNode != null) {
            relative(childNode);
        }
        if (conditionNodes != null) {
            for (int i = 0; i < conditionNodes.size(); i++) {
                relative(conditionNodes.getJSONObject(i));
            }
        }
    }

    private void process(JSONObject res) {
        JSONArray fid = res.getJSONArray("fid");
        JSONArray nid = res.getJSONArray("nid");
        nodes.add(getUnRelationNode(res));
        for (int i = 0; i < fid.size(); i++) {
            JSONObject link = new JSONObject();
            String fidId = fid.getString(i);
            String nidId = nid.getString(0);
            link.put("from",
                    fidId);
            link.put("to",
                    nidId);
            links.add(link);
        }
        if (res.containsKey("childNode")) {
            process(res.getJSONObject("childNode"));
        }
        if (res.containsKey("conditionNodes")) {
            JSONArray conditionNodes = res.getJSONArray("conditionNodes");
            for (int i = 0; i < conditionNodes.size(); i++) {
                process(conditionNodes.getJSONObject(i));
            }
        }
    }

    // 这是最原始的，controller要取，就从这里取
    public JSONObject initRelationsByData(Long processDefinitionId) {
        clear();
        EProcessDefinition eProcessDefinition = eProcessDefinitionMapper.selectById(processDefinitionId);
        JSONObject jsonObject = JSONObject.parseObject(eProcessDefinition.getJson());
        JSONObject processData = jsonObject.containsKey("approver") ? jsonObject.getJSONObject("approver")
                .getJSONObject("processData") : jsonObject.getJSONObject("processData");
        processData.put("fid",
                new JSONArray(Collections.singletonList(0)));
        processData.put("nid",
                new JSONArray(Collections.singletonList(processData.getString("nodeId"))));
        relative(processData);
        process(processData);
        JSONObject result = new JSONObject();
        result.put("nodes",
                nodes);
        links.stream()
                .map(res -> {
                    JSONObject fromNode = nodes.stream()
                            .map(res1 -> (JSONObject) res1)
                            .filter(res1 -> res1.getJSONObject("node")
                                    .getString("nodeId")
                                    .equals(res.getString("from")))
                            .findFirst()
                            .map(res1 -> (JSONObject) res1.getJSONObject("node"))
                            .orElse(null);
                    JSONObject toNode = nodes.stream()
                            .map(res1 -> (JSONObject) res1)
                            .filter(res1 -> res1.getJSONObject("node")
                                    .getString("nodeId")
                                    .equals(res.getString("to")))
                            .findFirst()
                            .map(res1 -> (JSONObject) res1.getJSONObject("node"))
                            .orElse(null);
                    res.put("fromNode",
                            fromNode);
                    res.put("toNode",
                            toNode);
                    return res;
                })
                .collect(Collectors.toList());
        result.put("links",
                links);
        return result;
    }

    // 获取节点的配置信息
    public JSONObject getRelationTargetNode(String nodeId,
            ArrayList<JSONObject> nodes) {
        JSONObject node = nodes.stream()
                .filter(jsonObject -> {
                    return jsonObject.get("key")
                            .equals(nodeId);
                })
                .findFirst()
                .orElse(null);
        if (node != null) {
            return node.getJSONObject("node");
        }
        return node;
    }

    // 提取筛选相关节点的方法
    public ArrayList<JSONObject> getRelatedNodes(ArrayList<JSONObject> links,
            String nodeId) {
        return links.stream()
                .filter(fv -> fv.getString("from")
                        .equals(nodeId))
                .collect(Collectors.toCollection(ArrayList::new));
    }

    // 获取实例里面，未处理的任务
    public List<EProcessTask> getUnapprovedTaskList(String processInstancesId) {
        // 查询当前实例下是否还有任务【审批中】，如果没有，则进入找下一个节点
        QueryWrapper<EProcessTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("process_instances_id",
                processInstancesId);
        queryWrapper.eq("task_status",
                TaskStatus.UNDER_APPROVAL.getValue());
        return eProcessTaskMapper.selectList(queryWrapper);
    }

    // 通过节点设计获取节点属性
    public JSONObject getNodeProperties(String nodeId,
            ArrayList<JSONObject> nodes) {
        JSONObject node = getRelationTargetNode(nodeId,
                nodes);
        return node.getJSONObject("properties");
    }

    // 通过节点设计获取审批标题
    public String getTitle(String nodeId,
            ArrayList<JSONObject> nodes) {
        JSONObject properties = getNodeProperties(nodeId,
                nodes);
        return properties.getString("title");
    }

    // 通过节点设计判断是否发起节点
    public Boolean getIsStart(String nodeId,
            ArrayList<JSONObject> nodes) {
        JSONObject node = getNodeByNodeId(nodeId,
                nodes);
        return node.getString("type")
                .equals("start");
    }

    // 通过节点列表设计获取会签
    public Boolean getCounterSignByNodeList(String nodeId,
            ArrayList<JSONObject> nodes) {
        JSONObject properties = getNodeProperties(nodeId,
                nodes);
        return properties.getBoolean("counterSign");
    }

    // 通过节点列表设计获取会签
    public Boolean getCounterSignByNode(JSONObject node) {
        JSONObject properties = node.getJSONObject("properties");
        return properties.getBoolean("counterSign");
    }

    // 获取节点类型
    public NodeType getToNodeType(JSONObject node) {
        return NodeType.getNodeTypeByValue(node.getString("type"));
    }

    // 通过节点设计获取审批人
    List<JSONObject> getApproversByNode(JSONObject node) {
        List<JSONObject> approverList = node.getJSONObject("properties")
                .getJSONArray("approvers")
                .toList(JSONObject.class);
        if (Objects.isNull(approverList)) {
            throw new RuntimeException("找不到审批人");
        }
        return approverList;
    }

    // 获取任务处理人
    public SysUser getApproverByTask(EProcessTask task) {
        Long userId = task.getApprover();
        return sysUserServiceImpl.selectUserById(userId);
    }

    // 根据节点id获取节点设计
    public JSONObject getNodeByNodeId(String processDesignId,
            ArrayList<JSONObject> nodes) {
        JSONObject jsonObject = nodes.stream()
                .filter(item -> {
                    return item.getString("key")
                            .equals(processDesignId);
                })
                .findFirst()
                .orElse(null);
        if (jsonObject.containsKey("node")) {
            return jsonObject.getJSONObject("node");
        }
        return null;
    }

    // 根据节点id获取节点设计
    public JSONObject getToNodeByNodeIdWithLinks(String processDesignId,
            ArrayList<JSONObject> links) {
        JSONObject jsonObject = links.stream()
                .filter(item -> {
                    JSONObject node = item.getJSONObject("fromNode");
                    return node.getString("nodeId")
                            .equals(processDesignId);
                })
                .findFirst()
                .orElse(null);
        if (jsonObject.containsKey("toNode")) {
            return jsonObject.getJSONObject("toNode");
        }
        return null;
    }

    // 获取流程设计中，实际申请人
    public SysUser getLiableUser(EProcessInstances eProcessInstances) {
        Long processDefinitionId = eProcessInstances.getProcessDefinitionId();
        JSONObject formValue = JSONObject.parseObject(eProcessInstances.getFormValue());
        SysUser liableUser = null;
        JSONObject jsonliableUser = getFieldsConfig(processDefinitionId).stream()
                .map(field -> (JSONObject) field)
                .filter(field -> field.getString("label")
                        .equals("实际申请人"))
                .findFirst()
                .orElse(null);
        if (jsonliableUser != null) {
            String vModel = jsonliableUser.getString("vModel");
            if (vModel != null) {
                JSONArray userJson = formValue.getJSONArray(vModel);
                if (userJson != null) {
                    String userId = userJson.getJSONObject(0)
                            .getString("value");
                    liableUser = sysUserServiceImpl.selectUserById(Long.parseLong(userId));
                }
            }
        }
        if (Objects.isNull(liableUser)) {
            throw new RuntimeException("找不到实际申请人");
        }
        return liableUser;
    }

    // 获取表单字段配置
    public JSONArray getFieldsConfig(Long processDefinitionId) {
        JSONObject formConfig = getFormConfig(processDefinitionId);
        if (getKit(processDefinitionId) == null) {
            return formConfig.getJSONArray("fields");
        } else {
            return formConfig.getJSONArray("children");
        }
    }

    // 获取表单配置
    public JSONObject getFormConfig(Long processDefinitionId) {
        EProcessDefinition eProcessDefinition = eProcessDefinitionMapper
                .selectEProcessDefinitionByID(processDefinitionId);
        JSONObject processDefinitionJson = JSONObject.parseObject(eProcessDefinition.getJson());
        JSONObject formConfig = null;
        if (getKit(processDefinitionId) == null) {
            return processDefinitionJson.getJSONObject("formData");
        } else {
            String kit = getKit(processDefinitionId);
            FlowType flowType = FlowType.getFlowTypeByName(kit);
            return (JSONObject) processDefinitionJson.getJSONObject("formData")
                    .getJSONArray("fields")
                    .get(0);
        }
    }

    // 获取套件
    public FlowType getFlowType(Long processDefinitionId) {
        if (getKit(processDefinitionId) == null) {
            return null;
        } else {
            return FlowType.getFlowTypeByName(getKit(processDefinitionId));
        }
    }

    // 获取套件
    public String getKit(Long processDefinitionId) {
        JSONObject formData = getFormData(processDefinitionId);
        if (formData.containsKey("kit")) {
            return formData.getString("kit");
        }
        return null;
    }

    // 获取表单数据
    public JSONObject getFormData(Long processDefinitionId) {
        EProcessDefinition eProcessDefinition = eProcessDefinitionMapper
                .selectEProcessDefinitionByID(processDefinitionId);
        JSONObject processDefinitionJson = JSONObject.parseObject(eProcessDefinition.getJson());
        return processDefinitionJson.getJSONObject("formData");
    }

    // 获取节点审批人数量
    public int getRequiredApprovalCount(String processDesignId) {
        // 当前节点id
        JSONObject node = getNodeByNodeId(processDesignId,
                (ArrayList<JSONObject>) nodes);
        Boolean counterSign = getCounterSignByNode(node);

        Integer count = 0;

        if (counterSign != null && counterSign) {
            List<JSONObject> approvers = getApproversByNode(node);
            count = approvers.size();
        } else {
            count = 1;
        }

        return count;
    }

    // 设置实例中，审批人审批通过的数量
    public EProcessInstances setEProcessInstancesApproverCount(EProcessInstances eProcessInstances,
            String type,
            Integer num) {
        Integer approvedCount = eProcessInstances.getNodeApprovedCount();
        if (type.equals("+")) {
            eProcessInstances.setNodeApprovedCount(approvedCount + num);
        } else if (type.equals("-")) {
            eProcessInstances.setNodeApprovedCount(approvedCount - num);
        }
        return eProcessInstances;
    }
}
